// 开发模式
const os = require("os");
// cpu核数
const threads = os.cpus().length;
// webpack内置了对js压缩的插件
const TerserPlugin = require("terser-webpack-plugin");
const path = require('path')
const ESLintPlugin = require('eslint-webpack-plugin');
// 通过插件自动引入js文件进入html文件 不需要手动引入main.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require("css-minimizer-webpack-plugin");

function getStyleLoaders(prev) {
  return [
    // 执行顺序:从右到左(从下到上)
    MiniCssExtractPlugin.loader,//由link标签引入css样式，避免出现闪屏现象，用户体验不好
    'css-loader',//将css资源编译成commonjs的模块到js中
    {
      loader: "postcss-loader",
      options: {
        postcssOptions: {
          plugins: [
            "postcss-preset-env", // 能解决大多数样式兼容性问题
          ],
        },
      },
    },
    prev
  ].filter(Boolean)// 排除掉空的undefined

}
module.exports = {
  // 入口
  entry: './src/main.js',
  // 输出
  output: {
    // 文件的输出路径
    // 1、将 dirname 解析为绝对路径。2将 'dist' 目录添加到 dirname 解析后的绝对路径后面。
    // 3、返回这两个路径片段组合后的完整绝对路径。
    // 所有文件的输出路径
    path: undefined,
    // js即入口文件的输出路径 css也打包成js了 
    filename: 'static/js/[name].js',
     // 给打包输出的其他文件命名
    chunkFilename:"static/js/[name].chunk.js",

     // 图片、字体等通过type：asset处理资源命名方式
     assetModuleFilename: "static/media/[name].[hash][ext]", // 图片、字体等资源命名方式（注意用hash）
    // 自动清空上次打包的dist
    // clean:true,
  },
  // 加载器  对象为单数，数组的名称为复数
  module: {
    rules: [
      {
        // 顾名思义就是只能匹配上一个 loader, 剩下的就不匹配了 节省时间
        oneOf: [
          {
            // 用来匹配 .css 结尾的文件
            test: /\.css$/,
            // use 数组里面 Loader 执行顺序是从右到左
            use: getStyleLoaders(),
          },
          {
            test: /\.less$/,
            use:getStyleLoaders('less-loader'),
          },
          {
            test: /\.s[ac]ss$/,
            use: getStyleLoaders('sass-loader'),
          },
          {
            test: /\.styl$/,
            use: getStyleLoaders('stylus-loader'),
          },
          {
            test: /\.(png|jpe?g|gif|webp)$/,
            type: "asset",
            parser: {
              dataUrlCondition: {
                maxSize: 10 * 1024, // 小于10kb的图片会被base64处理
              },
            },
            // generator: {
            //   // 将图片文件输出到 static/imgs 目录中
            //   // 将图片文件命名 [hash:8][ext][query]
            //   // [hash:8]: hash值取8位
            //   // [ext]: 使用之前的文件扩展名
            //   // [query]: 添加之前的query参数
            //   filename: "static/imgs/[hash:8][ext][query]",
            // },
          },
          {
            test: /\.(ttf|woff2?)$/,
            type: "asset/resource",
            // generator: {
            //   filename: "static/media/[hash:8][ext][query]",
            // },
          },
          {
            test: /\.js$/,
           // exclude: /node_modules/, // 排除node_modules代码不编译
           include: path.resolve(__dirname, "../src"), // 也可以用包含
           use: [
            {
              loader: "thread-loader", // 开启多进程
              options: {
                workers: threads, // 数量
              },
            },
            {
              loader: "babel-loader",
              options: {
                cacheDirectory: true, // 开启babel编译缓存
                cacheCompression: false, // 缓存文件不要压缩
                plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
              },
            },
          ],
          },
        ],
      },
    ],
  },
  // 插件
  plugins: [
    new ESLintPlugin({
      // 检测哪些文件
      context: path.resolve(__dirname, '../src'),
      exclude: "node_modules", // 默认值
      cache: true, // 开启缓存
      // 缓存目录
      cacheLocation: path.resolve(
        __dirname,
        "../node_modules/.cache/.eslintcache"
      ),
      threads, // 开启多进程
    }),
    new HtmlWebpackPlugin({
      // 模板：以public/index.html文件创建新的html文件
      // 新的html文件特点：1、结构和原来一致
      // 2、自动打包输出的资源
      template: path.resolve(__dirname, '../public/index.html')
    }),
    new MiniCssExtractPlugin({
      // 定义输出文件名和目录 
      filename: "static/css/[name].css",
      // 动态引入打包出来的资源名字
      chunkFilename: "static/css/[name].chunk.css"
    }),
   
    // css压缩
    // new CssMinimizerPlugin(),
  ]
  // plugins
  ,
  optimization: {
    minimize: true,
    minimizer: [
      // css压缩也可以写到optimization.minimizer里面，效果一样的
      new CssMinimizerPlugin(),
      // 当生产模式会默认开启TerserPlugin，但是我们需要进行其他配置，就要重新写了
      new TerserPlugin({
        parallel: threads // 开启多进程
      })
    ],
    splitChunks:{//会做什么事情？
      chunks:'all',//把nodemodules中的代码打包成一个单独的文件，用上了动态语法导入，会把动态导入文件打包成单独的文件，等需要时才会加载。
      // 其他的都用默认值
    }
  },
  // 开发服务器
  // 在开发模式下，没有输出资源，在内存中编译打包的
  devServer: {
    host: "localhost", // 启动服务器域名
    port: "3000", // 启动服务器端口号
    open: true, // 是否自动打开浏览器
    hot: true, // 开启HMR功能（只能用于开发环境，生产环境不需要了）
    // 在程序运行中，替换、添加或删除模块，而无需重新加载整个页面。只有这个模块需要重新打包编译即可。
  },
  // 模式
  mode: 'development',
  devtool: "cheap-module-source-map",

}